package com.box1312.fishpond;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class LevelStore implements LevelCommands {

  private final LevelDB db;

  public LevelStore(String dbPath, int cacheSize) {
    this.db = new LevelDB(dbPath, cacheSize);
  }

  @Override
  public byte[] set(String key, byte[] value) {
    db.set(LevelDB.bytes(key), value);
    return value;
  }

  @Override
  public String set(String key, String value) {
    set(key, LevelDB.bytes(value));
    return value;
  }

  @Override
  public byte[] get(byte[] key) {
    return db.get(key);
  }

  @Override
  public String get(String key) {
    return db.get(key);
  }

  @Override
  public Boolean exists(String key) {
    return db.exists(LevelDB.bytes(key));
  }

  @Override
  public void del(String... keys) {
    db.del(keys);
  }

  @Override
  public Long incrBy(String key, long increment) {
    return db.incrBy(key, increment);
  }

  @Override
  public Long incr(String key) {
    return incrBy(key, 1);
  }

  @Override
  public Long decrBy(String key, long decrement) {
    return incrBy(key, 0 - decrement);
  }

  @Override
  public Long decr(String key) {
    return incrBy(key, -1);
  }

  @Override
  public void hset(String key, String field, String value) {
    byte[] bHk = Utils.INSTANCE.hashKeyEncode(key, field);
    byte[] bValue = LevelDB.bytes(value);
    if (!exists(key)) {
      List<Entry<byte[], byte[]>> items = new ArrayList<Map.Entry<byte[], byte[]>>(2);
      Entry<byte[], byte[]> entry0 = new AbstractMap.SimpleEntry<byte[], byte[]>(LevelDB.bytes(key), EXIST);
      Entry<byte[], byte[]> entry1 = new AbstractMap.SimpleEntry<byte[], byte[]>(bHk, bValue);
      items.add(entry0);
      items.add(entry1);
      db.batchWrite(items);
    } else {
      db.set(bHk, bValue);
    }
  }

  @Override
  public String hget(String key, String field) {
    byte[] bHk = Utils.INSTANCE.hashKeyEncode(key, field);
    return LevelDB.asString(db.get(bHk));
  }

  @Override
  public void hdel(String key, String... field) {
    if (field != null && field.length > 0) {
      List<Entry<byte[], byte[]>> items = new ArrayList<Map.Entry<byte[], byte[]>>(field.length);
      for (String f : field) {
        byte[] bHk = Utils.INSTANCE.hashKeyEncode(key, f);
        Entry<byte[], byte[]> entry = new AbstractMap.SimpleEntry<byte[], byte[]>(bHk, null);
        items.add(entry);
      }
      db.batchWrite(items);
    }
  }

  @Override
  public Integer hlen(String key) {
    return null;
  }

  @Override
  public Boolean hexists(String key, String field) {
    byte[] bHk = Utils.INSTANCE.hashKeyEncode(key, field);
    return db.exists(bHk);
  }

  @Override
  public Map<String, String> hgetAll(String key) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Set<String> hkeys(String key) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public List<String> hvals(String key) {
    // TODO Auto-generated method stub
    return null;
  }

  public LevelIterator iterator(String start, String end) {
    return new LevelIterator(db, start, end);
  }

  @Override
  public void close() throws LevelStoreException {
    db.close();
  }

}
